from datetime import datetime
from time import time, sleep
import pytz
from flask import g, jsonify, request

from app.libs.redprint import Redprint
from app.libs.token_auth import auth
from app.libs.tools import generate_order_id
from app.models.AmountLog import AmountLog
from app.models.base import db
from app.models.user import User
from app.models.wxpay_order import wxpay_order
from app.validators.wxpay import WxPayPlaceOrder, CheckPayStatusForm
from app.wxpay.config import APPID
from app.wxpay.wxpay import WxPay

api = Redprint('wxpay')


@api.route("/place_order", methods=['POST'])
@auth.login_required
def place_order():
    form = WxPayPlaceOrder().validate_for_api()
    uid = g.user.uid

    user = User.query.filter_by(id=uid).first()
    payer = {
        'openid': user.mp_open_id
    }

    out_trade_no = generate_order_id()
    wxpay = WxPay()
    prepay_id = wxpay.place(payer, round(form.amount.data * 100), '1', out_trade_no)
    with db.auto_commit():
        wxpaymodel = wxpay_order()
        wxpaymodel.payer = uid
        wxpaymodel.out_trade_no = out_trade_no
        wxpaymodel.pay_amount = form.amount.data
        wxpaymodel.place_time = datetime.now(tz=pytz.timezone('Asia/Shanghai'))
        wxpaymodel.total_amount = form.amount.data
        wxpaymodel.prepay_id = prepay_id
        db.session.add(wxpaymodel)
        db.session.flush()
    timeStamp = str(int(time()))
    nonceStr = generate_order_id()
    resData = {
        'wxpaymodel': wxpaymodel,
        'parameters': {
            'timeStamp': timeStamp,
            'nonceStr': nonceStr,
            'package': f'prepay_id={prepay_id}',
            'signType': 'RSA',
            'paySign': wxpay.wxpay.sign([APPID, timeStamp, nonceStr, f'prepay_id={prepay_id}'])
        }
    }
    return jsonify(resData)


@api.route('/notify', methods=['POST'])
def notify():
    wxpay = WxPay()
    result = wxpay.wxpay.callback(request.headers, request.data)
    if result and result.get('event_type') == 'TRANSACTION.SUCCESS':
        resource = result.get('resource')
        appid = resource.get('appid')
        mchid = resource.get('mchid')
        out_trade_no = resource.get('out_trade_no')
        transaction_id = resource.get('transaction_id')
        trade_type = resource.get('trade_type')
        trade_state = resource.get('trade_state')
        trade_state_desc = resource.get('trade_state_desc')
        bank_type = resource.get('bank_type')
        attach = resource.get('attach')
        success_time = resource.get('success_time')
        payer = resource.get('payer')
        amount = resource.get('amount').get('total')

        with db.auto_commit():
            wxpayorder = wxpay_order.query.filter_by(out_trade_no=out_trade_no).first()
            if wxpayorder.transaction_id == '':
                wxpay_order.query.filter_by(out_trade_no=out_trade_no).update({
                    'transaction_id': transaction_id,
                    'trade_state': trade_state,
                    'appid': appid,
                    'mchid': mchid,
                    'trade_state_desc': trade_state_desc,
                    'bank_type': bank_type,
                    'attach': attach,
                    'trade_type': trade_type,
                    'pay_time': success_time
                })
                amount_log = AmountLog()
                amount_log.amount = wxpayorder.total_amount
                amount_log.modify_log = f'微信充值{str(wxpayorder.total_amount)}'
                amount_log.transaction_id = transaction_id
                amount_log.type = 'in'
                amount_log.user_id = wxpayorder.payer
                db.session.add(amount_log)

                User.query.filter_by(id=wxpayorder.payer).update({
                    'amount': User.amount + wxpayorder.total_amount
                })
        return jsonify({'code': 'SUCCESS', 'message': '成功'})
    else:
        return jsonify({'code': 'FAILED', 'message': '失败'}), 500


@api.route("/check_wx_order", methods=['POST'])
@auth.login_required
def check_pay_status():
    form = CheckPayStatusForm().validate_for_api()
    wxpay_order_info = wxpay_order.query.filter_by(out_trade_no=form.out_trade_no.data).first()
    if wxpay_order_info and wxpay_order_info.trade_state == 'SUCCESS':
        return jsonify({
            'error_code': 1000,
            'wxpay_order_info': wxpay_order_info
        })
    else:
        return jsonify({
            'error_code': 1109,
            'msg': '尚未支付'
        })
